package cn.ncu.wechat.Interceptor;

import cn.ncu.wechat.service.AdminService;
import cn.ncu.wechat.service.UserService;
import cn.ncu.wechat.util.Result;
import cn.ncu.wechat.util.StringUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.IOException;

@Component
public class WebInterceptor implements HandlerInterceptor{

    @Value("${cn.ncu.key}")
    private String key;
    @Autowired
    private UserService userService;
    @Autowired
    private AdminService adminService;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 使用拦截器实现JWT登录验证
     * */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
        //System.out.println(System.currentTimeMillis()+"拦截器收到请求");
        try {
            //获得token操作
            String authorization = request.getHeader("Authorization");
            System.out.println("authorization:"+authorization);
            if(authorization == null){
                return failResult(605,"请先登录！！",response);
            }
            //解密操作
            Algorithm algorithm = Algorithm.HMAC256(key);//设置加密方式
            JWTVerifier jwtVerifier = JWT.require(algorithm).build();//创建认证对象，创建失败会抛出AlgorithmMismatchException异常。
            DecodedJWT decodedJWT = jwtVerifier.verify(authorization.substring(7));//对去掉头信息的token进行验证
            String url = request.getRequestURI();
            String role = (String) redisTemplate.opsForValue().get(decodedJWT.getToken());
            System.out.println(role+"发出请求==================");
            if(url.startsWith("/api/wx")){
                if (StringUtil.IsNotNull(role)&&"user".equals(role)) return true;
                if (userService.checkURL(decodedJWT)){
                    return true;
                } else return failResult(401,"权限不足",response);
            }
            else if (url.startsWith("/api/admin") || url.startsWith("/api/miniapp") || url.startsWith("/api/upload") || url.startsWith("/upload")){
                if (StringUtil.IsNotNull(role)) return true;
                if (adminService.checkURL(decodedJWT)){
                    return true;
                } else return failResult(401,"权限不足",response);
            }
            else return false;
        } catch (JWTDecodeException e){
            return failResult(606,"秘钥格式错误！",response);
        } catch (SignatureVerificationException e){
            return failResult(607,"秘钥解密错误！",response);
        } catch (TokenExpiredException e) {
            return failResult(608,"token过期，请重新登录！",response);
        } catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 验证失败统一向前端返回错误结果
     * @param code 错误码
     * @param message 错误信息
     * @param response 响应对象
     * */
    public boolean failResult(int code ,String message, HttpServletResponse response){
        try {
            ObjectMapper objectMapper = new ObjectMapper();//使用jackson，也可以使用fastjson
            response.setStatus(code);
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding("UTF-8");
            response.getWriter().print( objectMapper.writeValueAsString(Result.error(code,message)));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
}
